# 首先你需要开启你的邮箱的「POP3/SMTP」和「IMAP/SMTP」服务，一般在邮箱设置的账户里，找找都能找到，注意开启后会获得一段「授权码」，牢记它！
# SMTP 服务器地址上网搜一下，对应邮箱服务商的

import time
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from datetime import datetime

# 从文件中读取配置，忽略注释部分，但保留格式
def read_config(filename="config.txt"):
    config = {}
    with open(filename, "r", encoding="utf-8") as f:
        lines = f.readlines()
    
    # 解析文件内容，并保留原始格式
    for line in lines:
        stripped_line = line.strip()
        # 去掉注释部分和行末空白字符
        if stripped_line and not stripped_line.startswith("#"):
            # 处理键值对
            key_value = stripped_line.split('=', 1)
            if len(key_value) == 2:
                key, value = key_value
                config[key.strip()] = value.split('#', 1)[0].strip()  # 删除注释部分
            
    return config, lines

# 将新的配置写回到文件中，保留原始格式
def write_config(filename="config.txt", config=None, original_lines=None):
    with open(filename, "w", encoding="utf-8") as f:
        config_keys = set(config.keys())  # 获取配置中的键集合
        
        for line in original_lines:
            stripped_line = line.strip()
            if stripped_line and not stripped_line.startswith("#"):
                # 如果行是有效的键值对，则写入更新的值
                key_value = stripped_line.split('=', 1)
                if len(key_value) == 2:
                    key, _ = key_value
                    if key in config:
                        f.write(f"{key}={config[key]}\n")
                        config_keys.discard(key)  # 已处理的键从集合中移除
                continue  # 跳过更新的配置行
            
            f.write(line)  # 保持原样写入空行和注释部分
        
        # 如果配置中有新的键（没有在原文件中出现），则追加到文件末尾
        for key in config_keys:
            f.write(f"{key}={config[key]}\n")

# 读取配置文件中的数据
config, original_lines = read_config()

# 配置参数
smtpserver = config['smtpserver']  # SMTP 服务器地址
username = config['username']  # 登录邮箱的用户名（通常是完整的邮箱地址）
password = config['password']  # 邮箱授权码
sender = config['sender']  # 发件人邮箱地址
receiver = config['receiver']  # 收件人邮箱地址

# 邮件内容设置
msg = MIMEMultipart('mixed')
subject = config['subject']  # 从配置文件读取邮件主题
body = config['body']  # 从配置文件读取邮件正文

msg['Subject'] = Header(subject, 'utf-8')  # 直接使用 Header 对象
msg['To'] = receiver
msg['From'] = sender
msg['Date'] = time.strftime('%Y-%m-%d %H:%M:%S')

text_plain = MIMEText(body, 'plain', 'utf-8')  # 使用从文件中读取的邮件正文
msg.attach(text_plain)

# 邮件发送计数，从配置文件读取
total = int(config['total'])  # 总共发送的邮件数
send = int(config['send'])  # 已发送邮件数
error = int(config['error'])  # 错误计数

# 获取配置文件中定义的开始发送时间
start_hour = int(config['start_hour'])  # 从配置文件中读取开始的小时
start_minute = int(config['start_minute'])  # 从配置文件中读取开始的分钟
interval = int(config['interval'])  # 从配置文件中读取每封邮件的间隔时间（秒）

# 定义一个函数来判断是否到达配置的开始时间
def is_time_to_send():
    now = datetime.now()
    return now.hour == start_hour and now.minute == start_minute  # 判断是否是指定时间

# 等待直到指定时间
while not is_time_to_send():
    print(f"当前时间: {datetime.now().strftime('%H:%M:%S')}，等待 1秒钟后再次检查...")
    time.sleep(1)  # 每10秒钟检查一次当前时间

# 发送邮件的循环
while error < 10 and send < total:
    try:
        # 连接并登录 SMTP 服务器，使用 SSL 加密
        smtp = smtplib.SMTP_SSL(smtpserver, 465)
        smtp.login(username, password)
        print("SMTP 连接成功，开始发送邮件")

        # 发送邮件
        while send < total:
            smtp.sendmail(sender, receiver, msg.as_string())
            send += 1
            error = 0  # 发送成功，重置错误计数
            print(f"第{send}封邮件发送成功！")
            time.sleep(interval)  # 每封邮件之间的间隔时间（从配置文件读取）

            # 更新配置文件中的发送计数
            config['send'] = str(send)
            config['error'] = str(error)
            write_config(config=config, original_lines=original_lines)

        # 退出 SMTP 会话
        smtp.quit()
        print("所有邮件发送完成，退出 SMTP 连接")
        break  # 邮件发送完毕后退出外层循环

    except smtplib.SMTPAuthenticationError as auth_error:
        print(f"SMTP 认证失败: {auth_error}")
        print(f"详细信息: {auth_error.smtp_code} - {auth_error.smtp_error}")
        error += 1
        config['error'] = str(error)  # 更新错误计数
        write_config(config=config, original_lines=original_lines)
        time.sleep(1)  # 如果发生认证错误，稍等 1 秒再重试

    except Exception as e:
        print(f"发生错误: {e}，重新发送")
        error += 1
        config['error'] = str(error)  # 更新错误计数
        write_config(config=config, original_lines=original_lines)
        time.sleep(1)  # 如果发生其他错误，稍等 1 秒再重试